package com.xbk.seckill.activity.application.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.xbk.seckill.activity.application.builder.SeckillActivityBuilder;
import com.xbk.seckill.activity.application.cache.service.SeckillActivityCacheService;
import com.xbk.seckill.activity.application.cache.service.SeckillActivityListCacheService;
import com.xbk.seckill.activity.application.command.SeckillActivityCommand;
import com.xbk.seckill.activity.application.service.SeckillActivityService;
import com.xbk.seckill.activity.application.service.fallback.SeckillActivityFallbackService;
import com.xbk.seckill.activity.domain.model.SeckillActivity;
import com.xbk.seckill.activity.domain.service.SeckillActivityDomainService;
import com.xbk.seckill.common.cache.model.SeckillBusinessCache;
import com.xbk.seckill.common.exception.ErrorCode;
import com.xbk.seckill.common.exception.SeckillException;
import com.xbk.seckill.common.model.dto.SeckillActivityDTO;
import com.xbk.seckill.common.model.enums.SeckillActivityStatus;
import com.xbk.seckill.common.utils.beans.BeanUtil;
import com.xbk.seckill.common.utils.id.SnowFlakeFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 秒杀活动
 *
 * @author xiexu
 * @date 2025/1/11 22:59
 */
@Service
public class SeckillActivityServiceImpl implements SeckillActivityService {

    @Autowired
    private SeckillActivityDomainService seckillActivityDomainService;

    @Autowired
    private SeckillActivityListCacheService seckillActivityListCacheService;

    @Autowired
    private SeckillActivityCacheService seckillActivityCacheService;

    /**
     * 保存活动信息
     * 
     * @param seckillActivityCommand 活动命令
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSeckillActivityDTO(SeckillActivityCommand seckillActivityCommand) {
        if (seckillActivityCommand == null) {
            throw new SeckillException(ErrorCode.PARAMS_INVALID);
        }
        SeckillActivity seckillActivity = SeckillActivityBuilder.toSeckillActivity(seckillActivityCommand);
        seckillActivity.setId(SnowFlakeFactory.getSnowFlakeFromCache().nextId());
        seckillActivity.setStatus(SeckillActivityStatus.PUBLISHED.getCode());
        seckillActivityDomainService.saveSeckillActivity(seckillActivity);
    }

    /**
     * 根据状态获取活动列表
     * 
     * @param status 状态
     * @return 活动列表
     */
    @Override
    public List<SeckillActivity> getSeckillActivityList(Integer status) {
        return seckillActivityDomainService.getSeckillActivityList(status);
    }

    /**
     * 根据时间和状态获取活动列表
     * 
     * @param currentTime 当前时间
     * @param status      状态
     * @return 活动列表
     */
    @Override
    public List<SeckillActivity> getSeckillActivityListBetweenStartTimeAndEndTime(Date currentTime, Integer status) {
        return seckillActivityDomainService.getSeckillActivityListBetweenStartTimeAndEndTime(currentTime, status);
    }

    @Override
    public SeckillActivity getSeckillActivityById(Long id) {
        return seckillActivityDomainService.getSeckillActivityById(id);
    }

    /**
     * 修改状态
     * 
     * @param status 状态
     * @param id     活动id
     */
    @Override
    public void updateStatus(Integer status, Long id) {
        seckillActivityDomainService.updateStatus(status, id);
    }

    /**
     * 根据状态和版本号获取活动列表
     * 
     * @param status  状态
     * @param version 版本号
     * @return 活动列表
     */
    @Override
    public List<SeckillActivityDTO> getSeckillActivityList(Integer status, Long version) {
        // 根据状态和版本号，从缓存中获取活动列表
        SeckillBusinessCache<List<SeckillActivity>> seckillActivitiyListCache = seckillActivityListCacheService.getCachedActivities(status, version);
        // 如果缓存中不存在活动列表，抛出异常
        if (!seckillActivitiyListCache.isExist()) {
            throw new SeckillException(ErrorCode.ACTIVITY_NOT_EXISTS);
        }
        // 稍后再试，前端需要对这个状态做特殊处理，即不去刷新数据，静默稍后再试
        if (seckillActivitiyListCache.isRetryLater()) {
            throw new SeckillException(ErrorCode.RETRY_LATER);
        }
        return seckillActivitiyListCache.getData().stream().map(seckillActivity -> {
            SeckillActivityDTO seckillActivityDTO = new SeckillActivityDTO();
            BeanUtil.copyProperties(seckillActivity, seckillActivityDTO);
            seckillActivityDTO.setVersion(seckillActivitiyListCache.getVersion());
            return seckillActivityDTO;
        }).collect(Collectors.toList());
    }

    /**
     * 获取活动信息，带有缓存
     *
     * @param id      活动id
     * @param version 版本号
     * @return
     */
//    @SentinelResource(value = "QUEUE-DATA-FLOW",
//            blockHandlerClass = SeckillActivityFallbackService.class, blockHandler = "getSeckillActivityBlockHandler",
//            fallbackClass = SeckillActivityFallbackService.class, fallback = "getSeckillActivityFallback")
    @Override
    public SeckillActivityDTO getSeckillActivity(Long id, Long version) {
        if (Objects.isNull(id)) {
            throw new SeckillException(ErrorCode.PARAMS_INVALID);
        }
        // 根据活动id和版本号，从缓存中获取活动信息
        SeckillBusinessCache<SeckillActivity> seckillActivityCache = seckillActivityCacheService.getCachedSeckillActivity(id, version);
        // 稍后再试，前端需要对这个状态做特殊处理，即不去刷新数据，静默稍后再试
        if (seckillActivityCache.isRetryLater()) {
            throw new SeckillException(ErrorCode.RETRY_LATER);
        }
        SeckillActivityDTO seckillActivityDTO = SeckillActivityBuilder.toSeckillActivityDTO(seckillActivityCache.getData());
        seckillActivityDTO.setVersion(seckillActivityCache.getVersion());
//        int i = 1 / 0;
        return seckillActivityDTO;
    }
}
